#include "D2DRenderer.h"
#include "Direct3DResource.h"

using namespace DirectXCore;

#pragma comment(lib, "dxgi")
#pragma comment(lib, "d2d1")
#pragma comment(lib, "dcomp")

D2DRenderer::D2DRenderer(HWND hWnd) : mWindowHandle(hWnd)
{
	// 位图通用属性
	mTargetBitmapProperties = std::make_unique<D2D1_BITMAP_PROPERTIES1>();
	mTargetBitmapProperties->pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
	mTargetBitmapProperties->pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
	mTargetBitmapProperties->bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;

	this->InitDirectComposition();
	this->InitD2DContext();
	this->InitRenderTarget();
}

D2DRenderer::~D2DRenderer() {
	// 1. 解绑D2D上下文与目标位图
	mD2DContext->SetTarget(nullptr);  // 关键：必须先解绑！

	// 2. 释放D2D资源（按依赖顺序）
	mTargetBitmap.Reset();     // 位图依赖上下文，但已解绑
	mD2DContext.Reset();      // 上下文依赖设备
	mD2DDevice.Reset();       // 设备依赖工厂
	mD2DFactory.Reset();

	// 3. 释放DirectComposition资源
	mRootCompositionVisual.Reset();  // 可能引用交换链，需先释放
	mCompositionTarget.Reset();
	mCompositionDevice.Reset();

	// 4. 释放DXGI资源
	mDXGISurface.Reset();     // 表面依赖交换链
	mSwapChain.Reset();
}

void D2DRenderer::InitDirectComposition()
{
	auto dxgiDevice = Direct3DResource::GetInstance()->GetDXGIDevice();

	DX_CALL(::DCompositionCreateDevice(dxgiDevice, IID_PPV_ARGS(&mCompositionDevice)));

	DX_CALL(mCompositionDevice->CreateTargetForHwnd(this->mWindowHandle, true, &mCompositionTarget));

	DX_CALL(mCompositionDevice->CreateVisual(mRootCompositionVisual.GetAddressOf()));
}

void D2DRenderer::InitD2DContext()
{
	auto dxgiDevice = Direct3DResource::GetInstance()->GetDXGIDevice();

	DX_CALL(::D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, IID_PPV_ARGS(&mD2DFactory)));

	DX_CALL(mD2DFactory->CreateDevice(dxgiDevice, &mD2DDevice));

	DX_CALL(mD2DDevice->CreateDeviceContext(
		D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
		&mD2DContext));
}

void D2DRenderer::Resize()
{
	// 1. 获取当前窗口尺寸
	RECT clientRect;
	GetClientRect(mWindowHandle, &clientRect);
	UINT newWidth = max(static_cast<UINT>(clientRect.right), 1);
	UINT newHeight = max(static_cast<UINT>(clientRect.bottom), 1);

	// 2. 获取当前交换链尺寸
	DXGI_SWAP_CHAIN_DESC1 swapChainDesc;
	DX_CALL(mSwapChain->GetDesc1(&swapChainDesc));

	// 3. 判断尺寸是否实际发生变化
	if (swapChainDesc.Width == newWidth && swapChainDesc.Height == newHeight) {
		return; // 尺寸未变化，无需更新
	}

	// 4. 安全释放旧资源
	// 必须重置 dc 上下文的渲染目标，否则交换链的 ResizeBuffers 会失败
	mD2DContext->SetTarget(nullptr);
	mDXGISurface.Reset();
	mTargetBitmap.Reset();

	// 5. 调整交换链尺寸
	DX_CALL(mSwapChain->ResizeBuffers(0,
		newWidth,
		newHeight,
		DXGI_FORMAT_UNKNOWN, 0));

	// 6. 重建渲染目标
	DX_CALL(mSwapChain->GetBuffer(0, IID_PPV_ARGS(&mDXGISurface)));
	DX_CALL(mD2DContext->CreateBitmapFromDxgiSurface(mDXGISurface.Get(), (*mTargetBitmapProperties), &mTargetBitmap));
	mD2DContext->SetTarget(mTargetBitmap.Get());

	// 7. 更新调试信息（可选）
#if defined(_DEBUG)
	OutputDebugStringW((std::wstring(L"SwapChain resized to: ") +
		std::to_wstring(newWidth) + L"x" +
		std::to_wstring(newHeight) + L"\n").c_str());
#endif
}

void D2DRenderer::InitRenderTarget()
{
	RECT rect;
	GetClientRect(mWindowHandle, &rect);

	DXGI_SWAP_CHAIN_DESC1 description = { 0 };
	description.Width = max(static_cast<UINT>(rect.right), 1);
	description.Height = max(static_cast<UINT>(rect.bottom), 1);
	// 自然的...透明的肯定是RGBA
	description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	description.SampleDesc.Count = 1;
	description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	description.BufferCount = 2;
	description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
	// 混合模式，这个模式带来的就是半透明的感觉
	description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;

	auto dxgiFactory = Direct3DResource::GetInstance()->GetDXGIFactory();
	auto dxgiDevice = Direct3DResource::GetInstance()->GetDXGIDevice();

	DX_CALL(dxgiFactory->CreateSwapChainForComposition(dxgiDevice, &description, nullptr, &mSwapChain));

	this->mRootCompositionVisual->SetContent(mSwapChain.Get());
	this->mCompositionTarget->SetRoot(this->mRootCompositionVisual.Get());

	// 设置渲染目标
	DX_CALL(mSwapChain->GetBuffer(0, IID_PPV_ARGS(&mDXGISurface)));
	DX_CALL(mD2DContext->CreateBitmapFromDxgiSurface(mDXGISurface.Get(), (*mTargetBitmapProperties), &mTargetBitmap));
	mD2DContext->SetTarget(mTargetBitmap.Get());
}

void D2DRenderer::Render()
{
	auto dc = mD2DContext.Get();
	dc->BeginDraw();
	dc->Clear();

	this->OnRender(dc);

	DX_CALL(dc->EndDraw());
	DX_CALL(mSwapChain->Present(1, 0));
	DX_CALL(this->mCompositionDevice->Commit());
}

void D2DRenderer::OnRender(ID2D1DeviceContext* dc)
{
	Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> brush;
	D2D1_COLOR_F color = { 255, 0, 0, 255 };
	auto hr = dc->CreateSolidColorBrush(color, brush.GetAddressOf());

	RECT rect;
	GetClientRect(mWindowHandle, &rect);

	D2D1_RECT_F rc = { 0 };
	rc.left = 0;
	rc.top = 0;
	rc.right = (float)rect.right;
	rc.bottom = (float)rect.bottom;

	D2D1_ROUNDED_RECT roundedRect = { 0 };
	roundedRect.radiusX = 100,
		roundedRect.radiusY = 100,
		roundedRect.rect = rc;

	dc->FillRoundedRectangle(roundedRect, brush.Get());
}

